import os
import config
import obj_config
import time
from transliterate import translit
import torch
import sounddevice as sd


class New_Speak:
    def __init__(self) -> None:
        self.check_internet_speak()
        try:
            self.settings()
        except BaseException:
            config.settings["type_sintez"] = ""

    def settings(
        self, language="ru", model_id="ru_v3", sample_rate=48000, speaker="baya"
    ):
        self.sample_rate = sample_rate
        self.speaker = speaker
        self.put_accent = True
        self.put_yoo = True
        self.device = torch.device("cpu")  # cpu или дри
        self.model, example_text = torch.hub.load(
            repo_or_dir="snakers4/silero-models",
            model="silero_tts",
            language=language,
            speaker=model_id,
        )
        self.model.to(self.device)

    def say_funk(self, _say: str) -> None:
        print(_say, "ffkkkkf")
        audio = self.model.apply_tts(
            text=_say,
            speaker=self.speaker,
            sample_rate=self.sample_rate,
            put_accent=self.put_accent,
            put_yo=self.put_yoo,
        )
        sd.play(audio, self.sample_rate)
        time.sleep(len(audio) / self.sample_rate)
        sd.stop()

    def check_internet_speak(self):
        net_boll = obj_config.service_functions_obj.check_internet()
        if net_boll and config.settings["type_sintez"] == "new":
            config.settings["type_sintez"] = "new"
        else:
            config.settings["type_sintez"] = ""


class Speak:
    def param(self, rate=0.15, pitch=-0.04) -> None:
        """Setter изменнения парметров синтезатора речи

        Праметры:
        `rate`: rate
        `pitch`: pitch
        """
        config.rate = rate
        config.pitch = pitch

    def speak(self, say_all: str) -> None:
        say_all = say_all.replace("  ", "")
        say_en = ""
        say_ru = ""
        say_mess = ""
        language_flag = ""
        for say in say_all.split(","):
            for word_i in say:
                if (word_i in config.dict_value_str_voice["dict_word"]):
                    if language_flag == "ru":
                        say_mess += say_ru
                        say_ru = ""
                    say_en += word_i
                    language_flag = "en"
                else:
                    if language_flag == "en":
                        text = translit(say_en, "ru")
                        say_mess += text
                        say_en = ""
                    say_ru += word_i
                    language_flag = "ru"
            if len(say_en) != 0:
                say_mess += translit(say_en, "ru")
            elif len(say_ru) != 0:
                say_mess += say_ru
            self.__say_funk(say_mess)
            say_mess = ""
            say_en = ""
            say_ru = ""
            language_flag = ""

    def corpus_lang(self, text, lang="ru"):
        """Функция исправления конкатенации строк сообщений

        Возращает:
        **Строку**
        """
        list_text = text.split(" ")
        return " ".join(list_text)

    def __say_funk(self, _say: str, lang="ru") -> None:
        if config.settings["type_sintez"] == "new" and lang == "ru":
            _say = self.corpus_lang(_say, lang)
            obj_config.new_speak_ru.say_funk(_say)
        elif config.settings["type_sintez"] == "new" and lang == "en":
            _say = self.corpus_lang(_say, lang)
            obj_config.new_speak_en.say_funk(_say)
        else:
            # _say = str(_say.encode('utf-8'))
            if lang == "ru":
                _say = self.corpus_lang(_say, lang)
                os.system(
                    f"echo {_say} |RHVoice-test -s {config.dict_value_str_voice['voice_name']} --rate {config.rate} --pitch {config.pitch} | aplay"
                )
                # echo "Привет" |RHVoice-client -s Anna  --rate 0,2 --pitch 0,05 | aplay
                # echo "Проверка синтезатора речи" | spd-say -o rhvoice -l ru -e -t
                # female1
                os.system(f"echo {_say} | spd-say -o rhvoice -l ru -e -t female1")

            else:
                _say = self.corpus_lang(_say, lang)
                # os.system(f"echo {_say} |RHVoice-client -s {config.dict_value_str_voice['voice_name_en']} --rate {config.rate} --pitch {config.pitch} | aplay")
                # os.system(f"echo {_say} |RHVoice-test -s {config.dict_value_str_voice['voice_name_en']} --rate {config.rate} --pitch {config.pitch} | aplay")
                os.system(f"echo {_say} | spd-say -o rhvoice -l ru -e -t female1")

    def kill(self) -> None:
        os.system("pkill -9 RHVoice-client")

    def _replace_word(self, _say_mess: str) -> str:
        """
        Замена сокращений в фразе на полные слова

        Например:
        ' тыс. ' на ' тысяч '

        Возращает:
        **Исправленную строку**
        """

        for r_i in range(len(config.dict_value_str_voice["rep_word"])):
            if _say_mess.find(config.dict_value_str_voice["rep_word"][r_i]) != -1:
                _say_mess = _say_mess.replace(
                    config.dict_value_str_voice["rep_word"][r_i],
                    config.dict_value_str_voice["rep_word_end"][r_i],
                )
        return _say_mess


class Сommunication(Speak):
    def __init__(self):
        self.__menu_list = config.default_modul
        self.__modul_value = []
        self.message_timer = 60
        self.__index_waiting = 0

    def message_typle(self, mess):
        if mess is not None:
            if mess:
                if isinstance(mess, str):
                    self.scheduler_message(("str_mess", mess))
                elif isinstance(mess, tuple):
                    self.scheduler_message(mess)
                else:
                    pass

    def event_message(self):
        # and ((time.time()%60)==0 and config.message_read==True)
        if not config.message_blocking:
            if (
                config.queue_message_external_events.qsize() > 0
                and config.event_message == "cheek_message"
            ):
                if (
                    config.time_out_mess_len == 0
                    or (config.time_out_mess_start + config.time_out_mess_len)
                    <= time.time()
                ):
                    if not config.queue_message_external_events.empty():
                        self.message(
                            f"У вас {config.queue_message_external_events.qsize()} сообщение Желаете озвучить"
                        )
                        cmd_str = obj_config.obj_api.queue_voice_time_str_api()
                        # cmd_str = config.stream_speech.get()
                        value = obj_config.decoders_obj.dec_function_recognition_keys(
                            cmd_str, "other"
                        )
                        print(value)
                        if "yes" in value:
                            config.time_out_mess_start = 0
                            config.time_out_mess_len = 0
                            while not config.queue_message_external_events.empty():
                                if config.queue_message_external_events.empty():
                                    self.scheduler_message(
                                        config.queue_message_external_events.get()
                                    )
                                return "yes"
                        elif "no" in value:
                            config.time_out_mess_start = time.time()
                            config.time_out_mess_len = 3600
                            self.message("Отсрочка на час")
                            return "Yes"
                        elif "clear" in value:
                            config.time_out_mess_start = 0
                            config.time_out_mess_len = 0
                            return "clear"
                        elif "exit" in value:
                            return "exit"
                        elif not cmd_str:
                            self.message("Время ожидание истекло")
                            config.time_out_mess_len = 120
                            return "exit"
            elif config.event_message == "event_message":
                while not config.queue_message_external_events.empty():
                    if config.queue_message_external_events.empty():
                        self.scheduler_message(
                            config.queue_message_external_events.get()
                        )
                # config.queue_message_external_events.queue.clear()

    def scheduler_message(self, message_tuple):
        if isinstance(message_tuple, tuple):
            if len(message_tuple) > 1:
                type_mess = message_tuple[0]
                mess = message_tuple[1]
                if type_mess == "str_mess":
                    self.message(mess)
                elif type_mess == "dict_menu":
                    obj_config.wrapper_decoders_obj.dict_menu_mess(mess)
                elif type_mess == "list_mess":
                    self.list_menu(mess)
                elif type_mess == "html_mess":
                    pass
                elif type_mess == "dict_html_and_mess":
                    # key1: mess_str
                    # key2: html
                    # key3: ???
                    pass
                elif type_mess == "api":
                    pass

    def __voice(self, messege: str) -> None:
        if config.stop_sr.qsize() >= 5:
            config.stop_sr.queue.clear()
        else:
            pass
        for word in config.dict_value_str_voice["del_word"]:
            messege = messege.replace(word, " ")
        config.stop_sr.put("False")
        obj_config.obj_Speak.speak(messege)
        config.stop_sr.put("True")

    def __print_message(self, messege: str) -> None:
        print(f"{config.name_voice_help.capitalize()}: {messege}")

    def man_question(self) -> None:
        # mess = f"<p><h1>{config.speech_recognition_str_api}</h1></p>"
        print(f"Вы сказали: {config.speech_recognition_str_api}\n")

    def __write_file(self, messege: str) -> None:
        file = open("voice_file.txt", "a")
        file.write(f"{messege}\n")
        file.close()

    def messege_menu(self, menu: list) -> None:
        obj_config.service_functions_obj.util_meta_data(menu, "modul_message.txt")
        self.__menu_list = menu

    def message(self, str_messege) -> None:
        if isinstance(str_messege, str):
            pass
        elif isinstance(str_messege, list):
            str_messege = self.corpus_lang(str_messege)

        else:
            str_messege = f"{str_messege}"

        str_messege = str(str_messege)
        config.comuniction_str_api = str_messege
        str_messege = self._replace_word(str_messege)
        obj_config.service_functions_obj.util_meta_data(
            str_messege, "modul_message.txt"
        )
        if len(config.buff_list_mess_comm["mess"]) >= config.buff_mess_comm_count:
            config.buff_list_mess_comm = {"mess": [], "data": []}
        config.buff_list_mess_comm["mess"].append(str_messege)
        config.buff_list_mess_comm["data"].append(time.time())
        config.message_blocking = True
        for menu in self.__menu_list:
            if menu == "core_modul_voice":
                self.__voice(str_messege)
            elif menu == "core_modul_print_message":
                self.__print_message(str_messege)
            elif menu == "core_modul_write_file":
                self.__write_file(str_messege)
            else:
                pass
        config.message_blocking = False
        # self.event_message()

    def modul_voice_activ(self, func):
        if not (func in self.__modul_value) and func != "clear":
            self.__modul_value.append(func)
        elif (func in self.__modul_value) and func != "clear":
            pass
        elif func == "clear":
            self.__modul_value.clear()

    def turning_on_message(self, message, level_message=0) -> None:
        if config.turning_message:
            self.message(message)
        elif level_message == 1:
            self.message(message)
        else:
            pass

    def message_stop_or_play(self):
        if self.__menu_list:
            self.__menu_list = []
        else:
            self.__menu_list = config.default_modul

    def list_message_enter(
        self, list_message, key_json="list_message_enter_dict_cmds", len_print_mess=5
    ):
        loop_main = True
        mini_loop_main = True
        cmd_make = ""
        iter_mess = len_print_mess
        old_iter_mess = 0
        while loop_main:
            if loop_main and old_iter_mess != iter_mess:
                print(old_iter_mess, iter_mess)
                for x in range(old_iter_mess, iter_mess):
                    obj_config.communication_obj.messege(list_message[x])
                cmd_make = ""
            while mini_loop_main:
                if mini_loop_main:
                    cmd_make = obj_config.wrapper_decoders_obj.decoder_rewind_and_index(
                        key_json
                    )
                if len(cmd_make) != 0:
                    mini_loop_main = False
            mini_loop_main = True
            if cmd_make == "end":
                loop_main = False
            elif cmd_make:
                if cmd_make == "repeat":
                    if (old_iter_mess - len_print_mess) != 0 and (
                        len(list_message) - iter_mess
                    ) == len_print_mess:
                        iter_mess = old_iter_mess
                        old_iter_mess -= len_print_mess
                    elif (len(list_message) - iter_mess) < len_print_mess:
                        old_iter_mess = iter_mess
                        iter_mess += len(list_message) - iter_mess
                elif cmd_make == "back":
                    if (
                        (old_iter_mess * 2 - len_print_mess) != 0
                        and (len(list_message) - iter_mess * 2) == len_print_mess
                        and (old_iter_mess * 2 - len_print_mess) < len_print_mess
                    ):
                        iter_mess = old_iter_mess * 2
                        old_iter_mess -= len_print_mess * 2
                    elif (len(list_message) - iter_mess * 2) < len_print_mess:
                        old_iter_mess = iter_mess
                        iter_mess += len(list_message) - iter_mess
                elif cmd_make == "end":
                    loop_main = False
                elif cmd_make == "forward":
                    if (iter_mess + len_print_mess) < len(list_message):
                        old_iter_mess = iter_mess
                        iter_mess += len_print_mess
                    else:
                        old_iter_mess = iter_mess
                        iter_mess += len(list_message) - iter_mess

                else:
                    pass
        return True

    def iter_list_mess(self, list_mess):
        try:
            for mess in list_mess:
                self.message(mess)
        except BaseException:
            self.message("Ошибка идексав модуле сообщений")

    def list_menu(self, list_mess):
        exit_flag = False
        iter_step = 5
        iter_mess = 0
        len_data = len(list_mess)
        while not exit_flag:
            iter_mess, iter_step = obj_config.service_functions_obj.iterator(
                iter_mess, len_data, iter_step
            )
            typle_key_num = obj_config.obj_wrapper_calls_fun.key_or_num()
            if iter_step > 0:
                self.iter_list_mess(list_mess[iter_mess : iter_mess + iter_step])
            else:
                self.iter_list_mess(list_mess[iter_mess + iter_step : iter_mess])
            permission_key = typle_key_num[0]
            num = typle_key_num[1]
            if permission_key:
                if permission_key == "forward":
                    iter_mess += iter_step
                elif permission_key == "back":
                    iter_mess -= iter_step
                elif permission_key == "metka_end":
                    exit_flag = True
            elif num != -1:
                exit_flag = True

            iter_mess += iter_step
        return num
